package com.SouthernWall_404.AgeRight.Common.API.LockAPI;

import com.SouthernWall_404.AgeRight.Common.API.Capability.Locks;
import com.SouthernWall_404.AgeRight.Common.API.Capability.Provider.LocksProvider;
import com.SouthernWall_404.AgeRight.Common.Network.ModChannels;
import com.SouthernWall_404.AgeRight.Common.Network.Packets.S2C.LockS2CPack;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.ChestBlock;
import net.minecraft.world.level.block.DoorBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.*;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraftforge.network.PacketDistributor;

import java.util.*;
import java.util.function.BiFunction;

public class LockAPI {
    // 注册联合方块处理器
    private static final Map<Block, BiFunction<BlockPos, Level, List<BlockPos>>> MULTI_BLOCK_HANDLERS = new HashMap<>();

    static {
        // 注册箱子处理器
        MULTI_BLOCK_HANDLERS.put(net.minecraft.world.level.block.Blocks.CHEST, LockAPI::getChestAttachedBlocks);
        MULTI_BLOCK_HANDLERS.put(net.minecraft.world.level.block.Blocks.TRAPPED_CHEST, LockAPI::getChestAttachedBlocks);

        // 注册门处理器
        for (Block door : Arrays.asList(
                net.minecraft.world.level.block.Blocks.OAK_DOOR,
                net.minecraft.world.level.block.Blocks.SPRUCE_DOOR,
                net.minecraft.world.level.block.Blocks.BIRCH_DOOR,
                net.minecraft.world.level.block.Blocks.JUNGLE_DOOR,
                net.minecraft.world.level.block.Blocks.ACACIA_DOOR,
                net.minecraft.world.level.block.Blocks.DARK_OAK_DOOR,
                net.minecraft.world.level.block.Blocks.CRIMSON_DOOR,
                net.minecraft.world.level.block.Blocks.WARPED_DOOR,
                net.minecraft.world.level.block.Blocks.IRON_DOOR
        )) {
            MULTI_BLOCK_HANDLERS.put(door, LockAPI::getDoorAttachedBlocks);
        }

        // 可以在这里添加更多联合方块处理器
    }

    // 注册自定义联合方块处理器
    public static void registerMultiBlockHandler(Block block, BiFunction<BlockPos, Level, List<BlockPos>> handler) {
        MULTI_BLOCK_HANDLERS.put(block, handler);
    }

    // 获取箱子的关联方块
    private static List<BlockPos> getChestAttachedBlocks(BlockPos pos, Level level) {
        List<BlockPos> attachedBlocks = new ArrayList<>();
        attachedBlocks.add(pos);

        BlockState state = level.getBlockState(pos);
        if (state.getBlock() instanceof ChestBlock) {
            // 检查是否有相邻的箱子形成双箱
            ChestBlock chestBlock = (ChestBlock) state.getBlock();
            ChestType type = state.getValue(ChestBlock.TYPE);

            if (type != ChestType.SINGLE) {
                Direction facing = state.getValue(ChestBlock.FACING);
                Direction connectedDir = (type == ChestType.LEFT) ? facing.getClockWise() : facing.getCounterClockWise();
                BlockPos connectedPos = pos.relative(connectedDir);

                if (level.getBlockState(connectedPos).getBlock() == chestBlock) {
                    attachedBlocks.add(connectedPos);
                }
            }
        }

        return attachedBlocks;
    }

    // 获取门的关联方块
    private static List<BlockPos> getDoorAttachedBlocks(BlockPos pos, Level level) {
        List<BlockPos> attachedBlocks = new ArrayList<>();
        attachedBlocks.add(pos);

        BlockState state = level.getBlockState(pos);
        if (state.getBlock() instanceof DoorBlock) {
            DoorBlock doorBlock = (DoorBlock) state.getBlock();
            DoubleBlockHalf half = state.getValue(DoorBlock.HALF);

            // 找到门的另一部分
            BlockPos otherHalfPos = (half == DoubleBlockHalf.LOWER) ? pos.above() : pos.below();
            if (level.getBlockState(otherHalfPos).getBlock() == doorBlock) {
                attachedBlocks.add(otherHalfPos);
            }

            // 对于双开门，找到另一扇门
            if (state.hasProperty(BlockStateProperties.DOOR_HINGE)) {
                DoorHingeSide hinge = state.getValue(BlockStateProperties.DOOR_HINGE);
                Direction facing = state.getValue(BlockStateProperties.HORIZONTAL_FACING);
                Direction offsetDir = (hinge == DoorHingeSide.LEFT) ? facing.getCounterClockWise() : facing.getClockWise();

                BlockPos otherDoorPos = pos.relative(offsetDir);
                BlockState otherDoorState = level.getBlockState(otherDoorPos);

                if (otherDoorState.getBlock() == doorBlock &&
                        otherDoorState.getValue(BlockStateProperties.DOOR_HINGE) != hinge &&
                        otherDoorState.getValue(BlockStateProperties.HORIZONTAL_FACING) == facing) {
                    attachedBlocks.add(otherDoorPos);

                    // 添加另一扇门的另一部分
                    DoubleBlockHalf otherHalf = otherDoorState.getValue(DoorBlock.HALF);
                    BlockPos otherDoorOtherHalf = (otherHalf == DoubleBlockHalf.LOWER) ?
                            otherDoorPos.above() : otherDoorPos.below();
                    if (level.getBlockState(otherDoorOtherHalf).getBlock() == doorBlock) {
                        attachedBlocks.add(otherDoorOtherHalf);
                    }
                }
            }
        }

        return attachedBlocks;
    }

    // 获取方块的关联方块
    private static List<BlockPos> getAttachedBlocks(BlockPos pos, Level level) {
        BlockState state = level.getBlockState(pos);
        Block block = state.getBlock();

        // 检查是否有注册的处理器
        if (MULTI_BLOCK_HANDLERS.containsKey(block)) {
            return MULTI_BLOCK_HANDLERS.get(block).apply(pos, level);
        }

        // 默认返回自身
        return Collections.singletonList(pos);
    }

    public static UUID getLockId(BlockPos blockPos, Level level) {
        LevelChunk chunk = level.getChunkAt(blockPos);
        Locks locks = chunk.getCapability(LocksProvider.LOCKS).orElse(null);
        if (locks != null) {
            return locks.getUUID(blockPos);
        }
        return UUID.randomUUID();
    }

    public static void addLock(UUID uuid, BlockPos blockPos, Level level) {
        if (level.isClientSide()) return; // 只在服务端执行

        // 获取所有关联方块
        List<BlockPos> attachedBlocks = getAttachedBlocks(blockPos, level);

        // 为所有关联方块添加锁
        for (BlockPos pos : attachedBlocks) {
            LevelChunk chunk = level.getChunkAt(pos);
            Locks locks = chunk.getCapability(LocksProvider.LOCKS).orElse(null);
            if (locks != null) {
                // 移除可能存在的旧锁（避免重复）
                int existingIndex = locks.lockPoses.indexOf(pos);
                if (existingIndex != -1) {
                    locks.lockPoses.remove(existingIndex);
                    locks.lockUUID.remove(existingIndex);
                }

                // 添加新锁
                locks.lockUUID.add(uuid);
                locks.lockPoses.add(pos);
                chunk.setUnsaved(true); // 标记区块为脏，确保保存

                // 同步到所有客户端
                syncLocksToClients(chunk);
            }
        }
    }

    public static void removeLock(BlockPos blockPos, Level level) {
        if (level.isClientSide()) return; // 只在服务端执行

        // 获取所有关联方块
        List<BlockPos> attachedBlocks = getAttachedBlocks(blockPos, level);

        // 移除所有关联方块的锁
        for (BlockPos pos : attachedBlocks) {
            LevelChunk chunk = level.getChunkAt(pos);
            Locks locks = chunk.getCapability(LocksProvider.LOCKS).orElse(null);
            if (locks != null) {
                int index = locks.lockPoses.indexOf(pos);
                if (index != -1) {
                    locks.lockPoses.remove(index);
                    locks.lockUUID.remove(index);
                    chunk.setUnsaved(true); // 标记区块为脏，确保保存

                    // 同步到所有客户端
                    syncLocksToClients(chunk);
                }
            }
        }
    }

    public static boolean hasLock(BlockPos blockPos, Level level) {
        LevelChunk levelChunk = level.getChunkAt(blockPos);
        Locks locks = levelChunk.getCapability(LocksProvider.LOCKS).orElse(null);
        if (locks != null) {
            return locks.lockPoses.contains(blockPos);
        }
        return false;
    }

    public static boolean isKeyTo(BlockPos blockPos, Level level, UUID uuid) {
        LevelChunk levelChunk = level.getChunkAt(blockPos);
        Locks locks = levelChunk.getCapability(LocksProvider.LOCKS).orElse(null);
        if (locks != null) {
            UUID lockId = locks.getUUID(blockPos);
            if (lockId.equals(uuid)) {
                return true;
            }
        }
        return false;
    }

    // 同步锁数据到所有客户端
    public static void syncLocksToClients(LevelChunk chunk) {
        if (chunk.getLevel() instanceof ServerLevel serverLevel) {
            // 发送给所有正在观看这个区块的玩家
            ModChannels.INSTANCE.send(
                    PacketDistributor.TRACKING_CHUNK.with(() -> chunk),
                    new LockS2CPack(chunk)
            );
        }
    }

    // 当玩家进入区块时发送锁数据
    public static void syncLocksToPlayer(LevelChunk chunk, ServerPlayer player) {
        ModChannels.INSTANCE.send(
                PacketDistributor.PLAYER.with(() -> player),
                new LockS2CPack(chunk)
        );
    }
}